from dfx_utils.klass_helper import BaseData, SuperDict
from typing import Dict, List


class ApiSetting(SuperDict):
    """ api配置类 """

    def __init__(self, api_name: str, api_uri: str, method: str, sep='.', *args, **kwargs):
        super(ApiSetting, self).__init__(_sep=sep, *args, **kwargs)
        self.api_name = api_name
        self.api_uri = api_uri
        self.method = method
        self.data = BaseData()
        self.params = BaseData()
        self.headers = BaseData()
        self.rules: List[BaseData] = list()

    def __setitem__(self, key, value):
        key_name = f'{self.api_name}{self._sep}{key}'
        super(ApiSetting, self).__setitem__(key_name, value)

    def __getitem__(self, key):
        key_name = f'{self.api_name}{self._sep}{key}'
        return super(ApiSetting, self).__getitem__(key_name)

    def reset(self):
        self.data = BaseData()
        self.params = BaseData()
        self.headers = BaseData()

    def add_data(self, **kwargs):
        self.data += kwargs

    def add_headers(self, **kwargs):
        self.headers += kwargs

    def add_params(self, **kwargs):
        self.params += kwargs

    def add_rule(self, rule: BaseData):
        """
        :type: params/headers/data
        :required: True/False
        :name: param name
        :value_type: str/list ...
        """
        self.rules.append(rule)

    def __check(self):
        rule_map = {'params': self.params, 'headers': self.headers, 'data': self.data}
        for item in self.rules:
            value = rule_map.get(item.type, BaseData())[item.name]
            if item.required:
                if not value:
                    raise Exception(f'未发现参数{item()}')
                if value.__class__.__name__ != item.value_type:
                    raise Exception(f'参数类型错误[{item()}]')
            if item.type == 'data':
                self[item.name] = value

    def __str__(self):
        for item in self.rules:
            print('param_type: ', item.type)
            print('param_name: ', item.name)
            print('value_type: ', item.value_type)
            print('is_required: ', item.required)
            print('')
        return ''

    def __call__(self, *args, **kwargs):
        self.__check()
        return self.params(), self.headers(), super().__call__().get(self.api_name, {})


class ApiManager(BaseData):
    def __init__(self, manager_name: str, base_uri: str):
        super(ApiManager, self).__init__()
        self._base_uri = base_uri
        self._manager_name = manager_name

    def __getitem__(self, api_name):
        setting: ApiSetting = super().__getitem__(api_name)

        return setting

    def __getattribute__(self, api_name):
        try:
            return super(ApiManager, self).__getattribute__(api_name)
        except:
            return None

    def __call__(self, api_name: str, api_path: str, method: str, sep='.'):
        self[api_name] = ApiSetting(api_name, self._base_uri + api_path, method.lower(), sep)
        return self[api_name]


if __name__ == '__main__':
    manager = ApiManager('demo', 'https://www.baidu.com')
    api = manager('demo', '/demo', 'get')
    api.add_rule(BaseData(type='data', required=True, name='a.b', value_type='str'))
    api.add_rule(BaseData(type='data', required=True, name='a.c', value_type='str'))
    print(manager.demo())
    # tmp = ApiSetting('test', 'path', 'get')
    # tmp.add_rule(BaseData(type='data', required=True, name='a.b', value_type='str'))
    # tmp.add_rule(BaseData(type='data', required=True, name='c.b', value_type='str'))
    # tmp.data['a.b'] = 'dsfdasfsfads'
    # tmp.data['c.b'] = 'safdasfas'
    # tmp.add_data(**{'a.b': '12122', 'c.b': 'asfadsf'})
    # tmp.add_params(ccc='dafdas')
    # tmp.add_headers(sjfalds='safdsafasdfsda')

    # manager = ApiManager('test_manager', 'base_uri')
    # manager['test'] = tmp
    # print(manager.test)

# class ApiSetting(SuperDict):
#     def __init__(self, api_name: str, request_url: str, method: str, *args, **kwargs):
#         super(ApiSetting, self).__init__(*args, **kwargs)
#         self.data = BaseData()
#         self.method = method.lower()
#         self.api_name = api_name
#         self.request_url = request_url
#
#     def __getitem__(self, item):
#         key = f'{self.api_name}.{item}'
#         return super(ApiSetting, self).__getitem__(key)
#
#     def __setitem__(self, key, value):
#         key = f'{self.api_name}.{key}'
#         return super(ApiSetting, self).__setitem__(key, value)
#
#     def add(self, **kwargs):
#         """ 添加数据 """
#         self.data.add(**kwargs)
#
#     def reset(self):
#         """ 清除已有数据 """
#         self.data = BaseData()
#
#     def data_rule(self, key, rule, required=True):
#         """ 添加数据规则 """
#         tmp_key = f'data.{key}'
#         self[tmp_key] = (rule, required)
#
#     def __add_rule(self, typ, args: list):
#         self[typ] = args
#
#     def header_rule(self, *args):
#         """ 添加 header 规则 """
#         self.__add_rule('header', args)
#
#     def param_rule(self, *args):
#         """ 添加 param 规则 """
#         self.__add_rule('param', args)
#
#     def __check_data(self, data, setting: SuperDict = None, ret_data: dict = dict()):
#         """ 检查 post data """
#         tmp_data = ret_data
#         for key, val in setting.items():
#             if isinstance(val, dict):
#                 tmp_data[key] = tmp_data.get(key, {})
#                 self.__check_data(data, setting=val, ret_data=tmp_data[key])
#             else:
#                 if not getattr(data, key) and val[-1]:
#                     raise Exception(f'{self.api_name}: data({key}) not found')
#                 elif getattr(data, key).__class__.__name__ not in val[0] and val[-1]:
#                     raise Exception(f'{self.api_name}: data({key}) need {val[0]}, found {type(getattr(data, key))}')
#                 tmp_data[key] = getattr(data, key)
#         return ret_data
#
#     def __check(self, typ, data: BaseData):
#         """ 检查 param 和 header """
#         ret_data = BaseData()
#         for item in self.get(typ, []):
#             value = getattr(data, item)
#             if value is None:
#                 raise Exception(f'{self.api_name}: {typ}({item}) not found')
#             ret_data.add(**{item: value})
#         return ret_data()
#
#     def __check_param(self, data: BaseData):
#         """ 检查 param """
#         param_key = f'{self.api_name}.param'
#         return self.__check(param_key, data)
#
#     def __check_header(self, data: BaseData):
#         """ 检查 header """
#         header_key = f'{self.api_name}.header'
#         return self.__check(header_key, data)
#
#     def __call__(self):
#         """ 检查并返回 param/header/data """
#         headers = self.__check_header(self.data)
#         param = self.__check_param(self.data)
#         key = f'{self.api_name}.data'
#         ret_data = self.__check_data(self.data, self.get(key, {}))
#         ret_data = {k: v for k, v in ret_data.items() if v is not None}
#         return param, headers, ret_data
#
#
# class ApiSettingManager(dict):
#     def __init__(self, base_url: str = None, name: str = None):
#         self.name = name
#         self.base_url = base_url
#
#     def __call__(self, api_name, path, method) -> ApiSetting:
#         """ 创建并记录 api setting """
#         request_url = f'{self.base_url}{path}'
#         key = f'{self.name}.{api_name}'
#         self[key] = ApiSetting(key, request_url, method)
#         return self[api_name]
#
#     def __getitem__(self, item):
#         key = f'{self.name}.{item}'
#         return super(ApiSettingManager, self).__getitem__(key)
